import math
import sys

import pandas
from PySide6.QtWidgets import *
from PySide6.QtCore import Qt, QSize, QEvent
from PySide6.QtGui import QAction, QIcon, QColor

from Compute import TrueInclination, TrueThickness

class GeologyAnalysisApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.setup_dock_widgets()
        self.setup_central_area()
        self.setup_connections()

    def init_ui(self):
        self.setWindowTitle("三维地质勘探分析系统")
        self.setGeometry(100, 100, 1280, 720)
        self.setup_toolbar()
        self.statusBar().showMessage("就绪")

    def setup_toolbar(self):
        toolbar = self.addToolBar("主工具栏")
        toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        # 工具栏动作
        actions = [
            ("导入数据", "document-open", self.import_data),  # 解释这个参数:导入数据,图标,导入数据方法
            ("清空", "edit-clear", self.clear_data),
            ("导出", "document-save", self.export_data),
            ("3D视图", "3d", self.toggle_3d_view),
            ("表格", "table", self.toggle_table_view)
        ]

        for text, icon_name, handler in actions:  # 解释函数作用:循环添加工具栏按钮并连接槽
            action = QAction(QIcon.fromTheme(icon_name), text, self)  # 解释函数作用:创建一个动作
            action.triggered.connect(handler)  # 解释函数作用:连接动作的触发信号到槽
            toolbar.addAction(action)  # 解释函数作用:添加动作到工具栏

    def setup_dock_widgets(self):
        # 左侧树形视图（带折叠按钮）
        self.left_dock = CollapsibleDockWidget("勘探记录项", self)
        self.tree = QTreeWidget()
        self.tree.setHeaderHidden(True)
        self.populate_tree()
        self.left_dock.setWidget(self.tree)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.left_dock)

        # 右侧属性面板（带折叠按钮）
        self.right_dock = CollapsibleDockWidget("属性详情", self)
        self.property_grid = QTableWidget(0, 2)  # 解释:创建一个属性表格 (0,2)表示行数和列数
        self.setup_property_grid()
        self.right_dock.setWidget(self.property_grid)
        self.addDockWidget(Qt.RightDockWidgetArea, self.right_dock)  # 解释:将右侧属性面板添加到主窗口的右侧停靠区域

    def setup_central_area(self):
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(5, 5, 5, 5)

        # 数据表格控制栏
        table_control = QWidget()
        table_control_layout = QHBoxLayout(table_control)
        self.toggle_table_btn = QPushButton("隐藏表格")
        self.refresh_btn = QPushButton("刷新数据")
        table_control_layout.addWidget(self.toggle_table_btn)
        table_control_layout.addWidget(self.refresh_btn)

        # 创建表格容器
        table_container = QWidget()
        table_layout = QVBoxLayout(table_container)
        table_layout.setContentsMargins(0, 0, 0, 0)
        table_layout.setSpacing(0)

        # 创建表头表格（只显示表头）
        self.header_table = QTableWidget(3, 0)
        self.header_table.setMinimumHeight(90)
        self.header_table.setMaximumHeight(90)
        self.header_table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.header_table.horizontalScrollBar().setEnabled(False)

        # 数据表格（不显示表头）
        self.data_table = QTableWidget()
        self.data_table.horizontalScrollBar().valueChanged.connect(
            self.header_table.horizontalScrollBar().setValue)
        self.data_table.horizontalHeader().setVisible(False)

        table_layout.addWidget(self.header_table)
        table_layout.addWidget(self.data_table)

        # 设置数据表格
        self.setup_data_table()
        self.setup_table()
        self.setup_context_menu()

        # 使用QSplitter管理垂直布局
        splitter = QSplitter(Qt.Vertical)
        splitter.addWidget(table_container)
        splitter.setChildrenCollapsible(False)

        main_layout.addWidget(splitter)
        main_layout.addWidget(table_control)

    def setup_connections(self):
        self.tree.itemClicked.connect(self.update_property_view)
        self.toggle_table_btn.clicked.connect(self.toggle_table_visibility)

    def populate_tree(self):
        """初始化示例树形数据"""
        root = QTreeWidgetItem(self.tree, ["井眼轨迹参数"])
        layers = [
            ("MG1", "数据1", "#ff0000"),
            ("MG2", "数据2", "#00ff00"),
            ("MG3", "数据3", "#0000ff")
        ]
        for code, name, color in layers:
            item = QTreeWidgetItem([f"{code} - {name}"])  # 解释:创建树形视图的子项
            item.setData(0, Qt.UserRole, color)
            root.addChild(item)
        self.tree.expandAll()

    def setup_property_grid(self):
        """配置属性表格"""
        self.property_grid.setHorizontalHeaderLabels(["属性", "值"])
        self.property_grid.horizontalHeader().setStretchLastSection(True)
        self.property_grid.verticalHeader().setVisible(False)
        self.property_grid.setEditTriggers(QTableWidget.NoEditTriggers)  # 解释:设置表格不可编辑
        self.property_grid.setColumnWidth(0, 100)  # 解释:设置表格的列宽

        # 连接水平滚动条

    def setup_data_table(self):
        """配置数据表格"""
        headers = ["井深(m)", "井斜(°)", "方位(°)", "垂深(m)", "南北坐标(m)", "东西坐标(m)",
                   "闭合方位(m)", "闭合位移(m)", "视平位移(m)", "狗腿度(°/30m)", "纵坐标(X)", "横坐标(Y)"]

        # 设置表头表格
        self.header_table.setColumnCount(len(headers))
        self.header_table.setHorizontalHeaderLabels(headers)  # 解释:设置表头标签
        self.header_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  # 解释:设置表格的列宽自适应
        self.header_table.horizontalHeader().setVisible(False);  # 解释:设置表头的水平表头不可见
        # self.header_table.verticalHeader().setVisible(False);# 解释:设置表头的垂直表头不可见

        # # 在表头表格中只添加一行冻结的表头数据
        # for col, header in enumerate(headers):
        #     item = QTableWidgetItem(header)
        #     item.setBackground(Qt.lightGray)  # 设置背景色使其更明显
        #     item.setFlags(Qt.ItemIsEnabled)  # 设置为不可编辑
        #     self.header_table.setItem(0, col, item)
        # 第一行：表头
        for col, header in enumerate(headers):
            item = QTableWidgetItem(header)
            item.setBackground(Qt.lightGray)
            item.setForeground(Qt.black)
            item.setTextAlignment(Qt.AlignCenter)
            item.setFlags(Qt.ItemIsEnabled)  # 设置为不可编辑
            self.header_table.setItem(0, col, item)

        # 第二行：特征1（可编辑左侧单元格）
        feature1_item = QTableWidgetItem("特征1")
        feature1_item.setBackground(Qt.lightGray)
        feature1_item.setForeground(Qt.black)
        feature1_item.setTextAlignment(Qt.AlignCenter)
        feature1_item.setFlags(Qt.ItemIsEnabled)  # 设置为不可编辑
        self.header_table.setItem(1, 0, feature1_item)  # 解释:设置表头的第一行的第一个单元格的属性        # 第二行：特征1（可编辑左侧单元格）
        # 第三行：特征2（可编辑左侧单元格）
        feature2_item = QTableWidgetItem("特征2")
        feature2_item.setBackground(Qt.lightGray)
        feature2_item.setForeground(Qt.black)
        feature2_item.setTextAlignment(Qt.AlignCenter)
        feature2_item.setFlags(Qt.ItemIsEnabled)  # 设置为不可编辑
        self.header_table.setItem(2, 0, feature2_item)  # 解释:设置表头的第一行的第一个单元格的属性

        # 其他单元格置空但设为可编辑
        for row in range(1, 3):
            for col in range(0, len(headers)):
                item = QTableWidgetItem("")
                if col == 0:
                    item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)  # 设置为可编辑
                else:
                    item.setFlags(Qt.ItemIsEnabled)  # 设置为不可编辑
                    item.setBackground(QColor(240, 240, 240))
                self.header_table.setItem(row, col, item)

        # 设置数据表格
        self.data_table.setColumnCount(len(headers))
        # 不设置表头标签，因为已经在header_table中显示了
        self.data_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # 同步两个表格的列宽
        for col in range(len(headers)):
            width = self.header_table.columnWidth(col)
            self.data_table.setColumnWidth(col, width)

        # # 连接水平滚动条
        # self.data_table.horizontalScrollBar().valueChanged.connect(
        #     self.header_table.horizontalScrollBar().setValue)

        # 添加数据变更事件处理
        self.data_table.itemChanged.connect(self.calculate_row_values)

        # 用于避免递归计算的标志
        self.is_calculating = False

        # 连接特征值变化事件
        self.header_table.itemChanged.connect(self.on_feature_changed)# 解释:连接特征值变化事件

        # 示例数据
        self.load_sample_data()

    def load_sample_data(self):
        # data = [
        #     ["MG1", "红粘土", 140, 35, 2.5],0.00	0.00	160.26
        # 32.87	0.27	160.26
        # 60.08	0.45	205.66
        # 87.61	0.53	281.06
        #     ["MG2", "砂质土", 240, 42, 3.0],
        #     ["MG3", "基岩", 500, 48, 4.2]
        # ]

        # 测试数据
        data = [
            [0.00, 0.00, 160.26, 0.00, 0, 0, 0, 0, 0, 0, 3246136.98, 18550536.42, ],
            [32.87, 0.27, 160.26, 32.87, - 0.07, 0.03, 160.26, 0.08, 0.07, 0.25, 3246136.91, 18550536.45],
            [32.87, 0.27, 160.26, 32.87, - 0.07, 0.03, 160.26, 0.08, 0.07, 0.25, 3246136.91, 18550536.45],
            [60.08, 0.45, 205.66, 60.08, - 0.23, 0.00, 179.62, 0.23, 0.23, 0.36, 3246136.75, 18550536.42],
            [87.61, 0.53, 281.06, 87.61, - 0.30, 0.00, 179.71, 0.30, 0.30, 0.66, 3246136.68, 18550536.42],
            [32.87, 0.27, 160.26, 32.87, - 0.07, 0.03, 160.26, 0.08, 0.07, 0.25, 3246136.91, 18550536.45],
            [60.08, 0.45, 205.66, 60.08, - 0.23, 0.00, 179.62, 0.23, 0.23, 0.36, 3246136.75, 18550536.42],
            [32.87, 0.27, 160.26, 32.87, - 0.07, 0.03, 160.26, 0.08, 0.07, 0.25, 3246136.91, 18550536.45],
            [60.08, 0.45, 205.66, 60.08, - 0.23, 0.00, 179.62, 0.23, 0.23, 0.36, 3246136.75, 18550536.42],
            [87.61, 0.53, 281.06, 87.61, - 0.30, 0.00, 179.71, 0.30, 0.30, 0.66, 3246136.68, 18550536.42],
            [32.87, 0.27, 160.26, 32.87, - 0.07, 0.03, 160.26, 0.08, 0.07, 0.25, 3246136.91, 18550536.45],
            [60.08, 0.45, 205.66, 60.08, - 0.23, 0.00, 179.62, 0.23, 0.23, 0.36, 3246136.75, 18550536.42],
            [60.08, 0.45, 205.66, 60.08, - 0.23, 0.00, 179.62, 0.23, 0.23, 0.36, 3246136.75, 18550536.42],
            [87.61, 0.53, 281.06, 87.61, - 0.30, 0.00, 179.71, 0.30, 0.30, 0.66, 3246136.68, 18550536.42],
            [32.87, 0.27, 160.26, 32.87, - 0.07, 0.03, 160.26, 0.08, 0.07, 0.25, 3246136.91, 18550536.45],
            [60.08, 0.45, 205.66, 60.08, - 0.23, 0.00, 179.62, 0.23, 0.23, 0.36, 3246136.75, 18550536.42],
            [87.61, 0.53, 281.06, 87.61, - 0.30, 0.00, 179.71, 0.30, 0.30, 0.66, 3246136.68, 18550536.42],
            [32.87, 0.27, 160.26, 32.87, - 0.07, 0.03, 160.26, 0.08, 0.07, 0.25, 3246136.91, 18550536.45],
            [60.08, 0.45, 205.66, 60.08, - 0.23, 0.00, 179.62, 0.23, 0.23, 0.36, 3246136.75, 18550536.42],
            [87.61, 0.53, 281.06, 87.61, - 0.30, 0.00, 179.71, 0.30, 0.30, 0.66, 3246136.68, 18550536.42]
        ]
        self.data_table.setRowCount(len(data))
        for row, items in enumerate(data):
            for col, value in enumerate(items):
                self.data_table.setItem(row, col, QTableWidgetItem(str(value)))

    def setup_table(self):
        self.data_table.setSelectionMode(QTableWidget.ContiguousSelection)  # 解释ContiguousSelection:连续选择
        self.data_table.setEditTriggers(QTableWidget.DoubleClicked)  # DoubleClicked:双击编辑
        # 安装事件过滤器处理按键事件
        self.data_table.installEventFilter(self)

    def eventFilter(self, obj, event):
        """事件过滤器，用于处理表格中的按键事件"""
        if obj == self.data_table and event.type() == QEvent.KeyPress:
            # 当按下回车键且不是在编辑状态
            if event.key() == Qt.Key_Return and not self.data_table.state() == QTableWidget.EditingState:
                current_row = self.data_table.currentRow()
                # 插入一行并移动焦点到新行的相同列
                self.data_table.insertRow(current_row + 1)
                self.data_table.setCurrentCell(current_row + 1, self.data_table.currentColumn())
                self.statusBar().showMessage(f"已在第 {current_row + 2} 行插入新行")
                return True  # 消费事件

            # Tab键移动焦点时自动扩展表格
            elif event.key() == Qt.Key_Tab:
                current_row = self.data_table.currentRow()
                current_col = self.data_table.currentColumn()

                # 如果是最后一列，添加新列
                if current_col == self.data_table.columnCount() - 1:
                    self.insert_column()

        # 其他事件正常处理
        return super().eventFilter(obj, event)

    def setup_context_menu(self):
        self.data_table.setContextMenuPolicy(Qt.CustomContextMenu)  # 改为自定义上下文菜单
        self.data_table.customContextMenuRequested.connect(self.show_context_menu)

        # 创建上下文菜单动作但不添加到表格
        self.paste_action = QAction("粘贴Excel数据", self)
        self.paste_action.triggered.connect(self.paste_excel_data)

        self.insert_row_action = QAction("插入行", self)
        self.insert_row_action.triggered.connect(self.insert_row)

        self.insert_column_action = QAction("插入列", self)
        self.insert_column_action.triggered.connect(self.insert_column)

        self.delete_row_action = QAction("删除行", self)
        self.delete_row_action.triggered.connect(self.delete_row)

        self.delete_column_action = QAction("删除列", self)
        self.delete_column_action.triggered.connect(self.delete_column)

    def show_context_menu(self, pos):
        """显示自定义上下文菜单"""
        menu = QMenu(self)
        menu.addAction(self.paste_action)
        menu.addSeparator()
        menu.addAction(self.insert_row_action)
        menu.addAction(self.insert_column_action)
        menu.addSeparator()
        menu.addAction(self.delete_row_action)
        menu.addAction(self.delete_column_action)

        # 在鼠标位置显示菜单
        menu.exec(self.data_table.viewport().mapToGlobal(pos))

    def insert_row(self):
        """插入行"""
        current_row = self.data_table.currentRow()
        if current_row >= 0:
            self.data_table.insertRow(current_row)
            self.statusBar().showMessage(f"已在第 {current_row + 1} 行插入新行")

    def insert_column(self):
        """插入列"""
        current_col = self.data_table.currentColumn()
        if current_col >= 0:
            # 在数据表格中插入列
            self.data_table.insertColumn(current_col)

            # 同时在表头表格中插入列
            if self.header_table.columnCount() <= current_col:
                self.header_table.insertColumn(current_col)

            # 添加表头
            new_header = f"新列{current_col + 1}"
            item = QTableWidgetItem(new_header)
            item.setBackground(Qt.lightGray)
            item.setFlags(Qt.ItemIsEnabled)
            self.header_table.setItem(0, current_col, item)

            # 同步列宽
            self.sync_column_widths()

            self.statusBar().showMessage(f"已在第 {current_col + 1} 列插入新列")

    def delete_row(self):
        """删除行"""
        current_row = self.data_table.currentRow()
        if current_row >= 0:
            self.data_table.removeRow(current_row)
            self.statusBar().showMessage(f"已删除第 {current_row + 1} 行")

    def delete_column(self):
        """删除列"""
        current_col = self.data_table.currentColumn()
        if current_col >= 0:
            # 删除数据表格中的列
            self.data_table.removeColumn(current_col)
            # 删除表头表格中的列
            self.header_table.removeColumn(current_col)
            self.statusBar().showMessage(f"已删除第 {current_col + 1} 列")

    def sync_column_widths(self):
        """同步表头表格和数据表格的列宽"""
        for col in range(self.data_table.columnCount()):
            width = self.data_table.columnWidth(col)
            self.header_table.setColumnWidth(col, width)

    def paste_excel_data(self):
        clipboard = QApplication.clipboard()
        data = clipboard.text()
        if not data:
            return

        current_row = self.data_table.currentRow()
        current_col = self.data_table.currentColumn()

        # 如果未选中单元格，默认从第一个单元格开始
        if current_row < 0:
            current_row = 0
        if current_col < 0:
            current_col = 0

        rows = data.split('\n')
        for i, row in enumerate(rows):
            if not row:
                continue
            column = row.split('\t')
            for j, value in enumerate(column):
                target_row = current_row + i
                target_column = current_col + j

                # 动态扩展表格
                if target_row >= self.data_table.rowCount():
                    self.data_table.insertRow(target_row)
                if target_column >= self.data_table.columnCount():
                    # 修正：使用insertColumn而不是insertRow
                    self.data_table.insertColumn(target_column)

                    # 同时扩展header_table
                    if self.header_table.columnCount() <= target_column:
                        self.header_table.insertColumn(target_column)
                        # 设置表头
                        header_item = QTableWidgetItem(f"列{target_column + 1}")
                        header_item.setBackground(Qt.lightGray)
                        header_item.setFlags(Qt.ItemIsEnabled)
                        self.header_table.setItem(0, target_column, header_item)

                # 设置单元格数据
                item = QTableWidgetItem(value.strip())
                self.data_table.setItem(target_row, target_column, item)

    def update_property_view(self, item):
        """更新属性表格内容"""
        self.property_grid.setRowCount(0)  # 解释:设置表格的行数

        # 示例属性数据
        properties = {
            "MG1 - 数据1": [
                ("设计方位", "188.00"),
                ("地磁偏角", "0.00"),
                ("特征1", " "),
                ("特征2", " "),
                ("上倾模式", "上倾下切、上倾上切"),
                ("底层倾角", "15"),
                ("真厚度", ""),
                ("下倾模式", "下倾下切，下倾上切"),
                ("底层倾角", "2"),
                ("真厚度", "")

            ],
            "MG2 - 数据2": [
                ("设计方位", "188.00"),
                ("地磁偏角", "0.00"),
                ("特征1", " "),
                ("特征2", " "),
                ("上倾模式", "上倾下切、上倾上切"),
                ("底层倾角", "15"),
                ("真厚度", ""),
                ("下倾模式", "下倾下切，下倾上切"),
                ("底层倾角", "2"),
                ("真厚度", "")

            ],
            "MG3 - 数据3": [
                ("设计方位", "188.00"),
                ("地磁偏角", "0.00"),
                ("特征1", " "),
                ("特征2", " "),
                ("上倾模式", "上倾下切、上倾上切"),
                ("底层倾角", "15"),
                ("真厚度", ""),
                ("下倾模式", "下倾下切，下倾上切"),
                ("底层倾角", "2"),
                ("真厚度", "")
            ],

            # 其他层数据...
        }

        if item.text(0) in properties:  # 解释:判断item.text(0)是否在properties中
            for prop in properties[item.text(0)]:  # 解释:遍历properties中的属性
                row = self.property_grid.rowCount()
                self.property_grid.insertRow(row)
                self.property_grid.setItem(row, 0, QTableWidgetItem(prop[0]))  # 解释:设置表格的单元格
                self.property_grid.setItem(row, 1, QTableWidgetItem(prop[1]))  # 解释:设置表格的单元格

    def toggle_table_visibility(self):
        """切换表格可见性"""
        container_visible = self.data_table.isVisible()
        self.header_table.setVisible(not container_visible)
        self.data_table.setVisible(not container_visible)
        self.toggle_table_btn.setText("显示表格" if container_visible else "隐藏表格")

    # 以下为功能占位方法
    def import_data(self):
        file_path, _ = QFileDialog.getOpenFileName(QWidget(self), "选择 Excel 文件", "C:\\",
                                                   "Excel Files (*.xls *.xlsx)")
        if file_path:
            try:
                self.df = pandas.read_excel(file_path)
                self.data_table.setRowCount(len(self.df))

                # 限制列数不超过表格的列数
                max_cols = min(len(self.df.columns), self.data_table.columnCount())

                for row in range(len(self.df)):
                    for col in range(max_cols):
                        # 防止空值导致的错误
                        value = self.df.iat[row, col] if not pandas.isna(self.df.iat[row, col]) else ""
                        self.data_table.setItem(row, col, QTableWidgetItem(str(value)))

                self.statusBar().showMessage(f"成功导入 {len(self.df)} 行数据")
            except Exception as e:
                QMessageBox.critical(self, "导入错误", f"导入Excel文件时出错：{str(e)}")

    # 解释:设置表格的单元格 几个参数:行,列,单元格内容
    # 解释:df.iat[row, col]是pandas库的方法,用于获取DataFrame的某个单元格的值

    def clear_data(self):
        self.tree.clear()
        self.property_grid.setRowCount(0)
        self.data_table.setRowCount(0)

    def export_data(self):
        pass

    def toggle_3d_view(self):
        pass

    def toggle_table_view(self):
        pass

    def calculate_row_values(self, changed_item):
            """当单元格数据变更时计算公式"""
            # 避免递归调用
            if hasattr(self, 'is_calculating') and self.is_calculating:
                return

            row = changed_item.row()
            col = changed_item.column()

            # 仅当修改井深、井斜或方位列时触发计算
            if col not in [0, 1, 2]:
                return

            try:
                self.is_calculating = True
                import math

                # 获取当前行数据
                current_depth = self.get_cell_value(row, 0)      # 井深
                current_inclination = self.get_cell_value(row, 1)  # 井斜
                current_azimuth = self.get_cell_value(row, 2)    # 方位

                if current_depth is None or current_inclination is None or current_azimuth is None:
                    return

                # 第一行特殊处理
                if row == 0:
                    # 简单计算第一行数据
                    vertical_depth = current_depth * math.cos(math.radians(current_inclination))
                    north_south = 0
                    east_west = 0
                    closed_orientation = current_azimuth
                    closed_displacement = 0
                    eye_displacement = 0
                    dogleg_degree = 0
                    ordinate_x = 3246136.98  # 初始纵坐标X
                    abscissa_y = 18550536.42  # 初始横坐标Y
                else:
                    # 获取上一行数据
                    prev_depth = self.get_cell_value(row-1, 0)  # 上一行井深
                    prev_inclination = self.get_cell_value(row-1, 1)  # 上一行井斜
                    prev_azimuth = self.get_cell_value(row-1, 2)  # 上一行方位
                    prev_vertical_depth = self.get_cell_value(row-1, 3)  # 上一行垂深
                    prev_north_south = self.get_cell_value(row-1, 4)  # 上一行南北坐标
                    prev_east_west = self.get_cell_value(row-1, 5)  # 上一行东西坐标
                    prev_ordinate_x = self.get_cell_value(row-1, 10)  # 上一行纵坐标X
                    prev_abscissa_y = self.get_cell_value(row-1, 11)  # 上一行横坐标Y

                    # 计算段长（当前井深 - 上一行井深）
                    segment = current_depth - prev_depth

                    # 垂深计算
                    min_curvature = 1.0
                    vertical_depth = prev_vertical_depth + segment/2 * (
                        math.cos(math.radians(prev_inclination)) +
                        math.cos(math.radians(current_inclination))
                    ) * min_curvature

                    # 计算南北坐标变化
                    ns_change = segment/2 * (
                        math.sin(math.radians(prev_inclination)) * math.cos(math.radians(prev_azimuth)) +
                        math.sin(math.radians(current_inclination)) * math.cos(math.radians(current_azimuth))
                    )
                    north_south = prev_north_south + ns_change

                    # 计算东西坐标变化
                    ew_change = segment/2 * (
                        math.sin(math.radians(prev_inclination)) * math.sin(math.radians(prev_azimuth)) +
                        math.sin(math.radians(current_inclination)) * math.sin(math.radians(current_azimuth))
                    )
                    east_west = prev_east_west + ew_change

                    # 计算闭合方位
                    if north_south == 0 and east_west == 0:
                        closed_orientation = 0
                    else:
                        closed_orientation = (math.degrees(math.atan2(east_west, north_south))) % 360

                    # 计算闭合位移和视平位移
                    closed_displacement = math.sqrt(north_south**2 + east_west**2)
                    eye_displacement = closed_displacement

                    # 计算狗腿度
                    if segment == 0:
                        dogleg_degree = 0
                    else:
                        cos_dogleg = math.cos(math.radians(current_inclination - prev_inclination)) - \
                                    math.sin(math.radians(prev_inclination)) * \
                                    math.sin(math.radians(current_inclination)) * \
                                    (1 - math.cos(math.radians(current_azimuth - prev_azimuth)))

                        # 限制cos_dogleg在[-1, 1]范围内
                        cos_dogleg = max(min(cos_dogleg, 1.0), -1.0)

                        dogleg_angle = math.degrees(math.acos(cos_dogleg))
                        # 标准化为每30米的狗腿度
                        dogleg_degree = dogleg_angle * 30 / segment

                    # 计算坐标
                    ordinate_x = prev_ordinate_x - ns_change
                    abscissa_y = prev_abscissa_y + ew_change

                # 设置计算结果
                self.set_cell_value(row, 3, round(vertical_depth, 2))
                self.set_cell_value(row, 4, round(north_south, 2))
                self.set_cell_value(row, 5, round(east_west, 2))
                self.set_cell_value(row, 6, round(closed_orientation, 2))
                self.set_cell_value(row, 7, round(closed_displacement, 2))
                self.set_cell_value(row, 8, round(eye_displacement, 2))
                self.set_cell_value(row, 9, round(dogleg_degree, 2))
                self.set_cell_value(row, 10, round(ordinate_x, 2))
                self.set_cell_value(row, 11, round(abscissa_y, 2))

                # 更新特征行计算
                self.update_feature_calculations()

                self.statusBar().showMessage(f"第{row+1}行数据计算完成")
            except Exception as e:
                self.statusBar().showMessage(f"计算错误: {str(e)}")
                print(f"计算错误: {str(e)}")
            finally:
                self.is_calculating = False
    def create_trajectory_data(self, row):# 解释:创建TrajectoryData对象
        """获取指定行的数据，创建TrajectoryData对象"""
        from TrajectoryData import TrajectoryData

        data = TrajectoryData()
        if row >= 0 and row < self.data_table.rowCount():
            data.wellDepth = self.get_cell_value(row, 0) or 0       # 井深
            data.wellSlope = self.get_cell_value(row, 1) or 0       # 井斜
            data.azimuth = self.get_cell_value(row, 2) or 0         # 方位
            data.verticalDepth = self.get_cell_value(row, 3) or 0   # 垂深
            data.nsCoordinates = self.get_cell_value(row, 4) or 0   # 南北坐标
            data.ewCoordinates = self.get_cell_value(row, 5) or 0   # 东西坐标
            data.closedOrientation = self.get_cell_value(row, 6) or 0  # 闭合方位
            data.closedDisplacement = self.get_cell_value(row, 7) or 0  # 闭合位移
            data.eyeDisplacement = self.get_cell_value(row, 8) or 0  # 视平位移
            data.doglegDegree = self.get_cell_value(row, 9) or 0   # 狗腿度
            data.ordinate = self.get_cell_value(row, 10) or 0      # 纵坐标
            data.abscissa = self.get_cell_value(row, 11) or 0      # 横坐标
        return data

    def get_cell_value(self, row, col):
        """获取单元格数值，处理空值和非数字值"""
        item = self.data_table.item(row, col)
        if item and item.text():
            try:
                return float(item.text())
            except ValueError:
                return None
        return None

    def set_cell_value(self, row, col, value):
        """设置单元格的值"""
        if value is None:
            value = ""
        else:
            value = str(round(value, 2) if isinstance(value, (int, float)) else value)

        # 确保行列数足够
        if row >= self.data_table.rowCount():
            self.data_table.setRowCount(row + 1)
        if col >= self.data_table.columnCount():
            self.data_table.setColumnCount(col + 1)

        item = QTableWidgetItem(value)
        self.data_table.setItem(row, col, item)

    def setup_feature_rows(self):
        """设置特征1和特征2行"""
        # 表头表格增加至3行
        if self.header_table.rowCount() < 3:
            self.header_table.setRowCount(3)

        # 第一行仍为表头，第二、三行为特征行

        # 第二行：特征1 - 上倾角度
        feature1_label = QTableWidgetItem("特征1(上倾角度)")
        feature1_label.setBackground(Qt.lightGray)
        feature1_label.setFlags(Qt.ItemIsEnabled)  # 不可编辑
        self.header_table.setItem(1, 0, feature1_label)

        input1_item = QTableWidgetItem("")
        input1_item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
        self.header_table.setItem(1, 1, input1_item)

        # 第三行：特征2 - 下倾角度
        feature2_label = QTableWidgetItem("特征2(下倾角度)")
        feature2_label.setBackground(Qt.lightGray)
        feature2_label.setFlags(Qt.ItemIsEnabled)  # 不可编辑
        self.header_table.setItem(2, 0, feature2_label)

        input2_item = QTableWidgetItem("")
        input2_item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
        self.header_table.setItem(2, 1, input2_item)

        # 预置结果单元格
        for row in [1, 2]:
            for col in range(2, 5):  # 2-4列用于显示结果
                result_item = QTableWidgetItem("")
                result_item.setFlags(Qt.ItemIsEnabled)  # 只读
                result_item.setBackground(QColor(240, 240, 240))
                self.header_table.setItem(row, col, result_item)

    def on_feature_changed(self, item):
        """处理特征值变更"""
        row = item.row()
        col = item.column()

        # 只处理特征行的输入列
        if row in [1, 2] and col == 1:
            self.update_feature_calculations()


    def update_feature_calculations(self):
        """更新特征计算结果"""
        try:
            last_row = self.data_table.rowCount() - 1
            if last_row < 1:  # 需要至少两行数据
                return

            # 获取最后两行数据
            from TrajectoryData import TrajectoryData

            data1 = self.create_trajectory_data(last_row - 1)
            data2 = self.create_trajectory_data(last_row)

            # 使用导入的TrueInclination和TrueThickness类
            from Compute import TrueInclination, TrueThickness
            ti = TrueInclination()
            tt = TrueThickness()

            # 处理特征1（上倾）
            feature1_item = self.header_table.item(1, 1)
            if feature1_item and feature1_item.text():
                try:
                    inclination1 = float(feature1_item.text())

                    # 计算真实倾角和厚度
                    true_inclination1 = ti.trueInclination(
                        data2.verticalDepth, data2.eyeDisplacement, inclination1, True)

                    true_thickness1 = tt.trueThickness(data1, data2, inclination1, True)

                    # 显示结果
                    result1 = QTableWidgetItem(f"真实倾角: {round(true_inclination1, 2)}°")
                    result1.setFlags(Qt.ItemIsEnabled)  # 只读
                    self.header_table.setItem(1, 2, result1)

                    result2 = QTableWidgetItem(f"真实厚度: {round(true_thickness1, 2)}m")
                    result2.setFlags(Qt.ItemIsEnabled)  # 只读
                    self.header_table.setItem(1, 3, result2)

                except ValueError:
                    pass

            # 处理特征2（下倾）
            feature2_item = self.header_table.item(2, 1)
            if feature2_item and feature2_item.text():
                # 同上，处理特征2的计算...
                pass
        except Exception as e:
            self.statusBar().showMessage(f"特征计算错误: {str(e)}")
            print(f"特征计算错误: {str(e)}")

        def get_row_data(self, row):
            """获取指定行的数据，转换为TrajectoryData对象"""
            from TrajectoryData import TrajectoryData

            data = TrajectoryData()
            if row >= 0 and row < self.data_table.rowCount():
                data.wellDepth = self.get_cell_value(row, 0) or 0       # 井深
                data.wellSlope = self.get_cell_value(row, 1) or 0       # 井斜
                data.azimuth = self.get_cell_value(row, 2) or 0         # 方位
                data.verticalDepth = self.get_cell_value(row, 3) or 0   # 垂深
                data.nsCoordinates = self.get_cell_value(row, 4) or 0   # 南北坐标
                data.ewCoordinates = self.get_cell_value(row, 5) or 0   # 东西坐标
                data.closedOrientation = self.get_cell_value(row, 6) or 0  # 闭合方位
                data.closedDisplacement = self.get_cell_value(row, 7) or 0  # 闭合位移
                data.eyeDisplacement = self.get_cell_value(row, 8) or 0  # 视平位移
                data.doglegDegree = self.get_cell_value(row, 9) or 0   # 狗腿度
                data.ordinate = self.get_cell_value(row, 10) or 0      # 纵坐标
                data.abscissa = self.get_cell_value(row, 11) or 0      # 横坐标
            return data


        def calculate_feature_result(self, feature_row, col, value):
            """计算特征值在各列的结果

            这里需要根据实际公式进行修改，示例使用简单计算
            """
            # 特征1公式
            if feature_row == 1:
                return value * (col * 1.5)
            # 特征2公式
            else:
                return value * (col / 2)


        def calculate_vertical_depth(self, row):
            """计算垂深
            公式: =IF(井深>0,上一位垂深+段数/2*(COS(上一位井斜深度)+COS(井斜深度))*最小曲率,"")
            """
            current_depth = self.get_cell_value(row, 0)  # 井深

            if current_depth is None or current_depth <= 0:
                return ""

            # 井斜角度(需转为弧度)
            current_inclination = self.get_cell_value(row, 1)
            if current_inclination is None:
                return ""

            # 第一行特殊处理
            if row == 0:
                previous_depth = 0
                previous_inclination = 0
                previous_vertical_depth = 0
            else:
                previous_depth = self.get_cell_value(row - 1, 0)
                previous_inclination = self.get_cell_value(row - 1, 1)
                previous_vertical_depth = self.get_cell_value(row - 1, 3)

                if any(val is None for val in [previous_depth, previous_inclination, previous_vertical_depth]):
                    return ""

            # 段数计算
            segment = current_depth - previous_depth

            # 最小曲率系数
            min_curvature = 1.0

            # 垂深计算公式
            vertical_depth = previous_vertical_depth + segment / 2 * (
                    math.cos(math.radians(previous_inclination)) +
                    math.cos(math.radians(current_inclination))
            ) * min_curvature

            return round(vertical_depth, 2)


class CollapsibleDockWidget(QDockWidget):
    """可折叠的停靠窗口"""

    def __init__(self, title, parent=None):
        super().__init__(title, parent)
        self.setFeatures(QDockWidget.DockWidgetClosable |
                         QDockWidget.DockWidgetMovable |
                         QDockWidget.DockWidgetFloatable)
        # 设置停靠窗口的特性: self.setFeatures(QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable) 这行代码设置停靠窗口的特性，使其可以关闭、移动和浮动。
        self.toggle_action = self.toggleViewAction()  # 这行代码获取停靠窗口的切换视图动作。
        self.toggle_action.setText("切换侧边栏" if "记录项" in title else "切换属性栏")
        # 这行代码设置切换动作的文本，如果标题中包含“记录项”，则文本为“切换侧边栏”，否则为“切换属性栏”。


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = GeologyAnalysisApp()
    window.show()
    sys.exit(app.exec())
